import itertools
import os
import sets
import sys
import datetime
from pprint import pformat

os.environ["DJANGO_SETTINGS_MODULE"] = "cconnect.settings" 
sys.path.append('../..')
#from django.template import Context
#from django.template.loader import get_template
#from django.contrib.sites.models import Site
from noonhat.lunch.models import Log, Match, Intent, IntentMatch
from noonhat.lunch import lunchutil
from noonhat.externals import geopy

date = datetime.date.today() + datetime.timedelta(days=1)
pretend = True
output = []

MAX_SIZE = 4

if pretend: 
    output.append("Running in pretend mode.")

available_intents = lunchutil.find_available_intents(date)
available_intents = [item for item in available_intents 
                                        if item.status == 'confirmed']
matchable_intents = []

output.append("#" * 70)
# Find any intents which just can't be matched (no one else nearby)
# Set their status to 'match_failed'
tempoutput = []
for i in available_intents:
    possible_matches = False
    radius = i.radius / 10
    #print i.id, i.created, i.lat, i.lng, radius
    for other in available_intents:
        if i.person_id != other.person_id:
            pair_distance = geopy.distance.distance((i.lat, i.lng), 
                    (other.lat, other.lng)).km
            #print " ", other.person_id, pair_distance, 
            #print (float(radius) + float(other.radius / 10)) - pair_distance,
            #print ((float(radius) + float(other.radius / 10)) - pair_distance) > 0
            if ((float(radius) + float(other.radius / 10)) - pair_distance) > 0:
                possible_matches = True
    if not possible_matches:
        message = 'No match found for %s on %s (I:%s)' % (
                i.person.email, i.date, i.id)
        if not pretend:
            i.status = 'match_failed'
            i.save()

            l = Log(intent = i, action = 'match_failed', message = message)
            l.save()
        tempoutput.append('F')
    else:
        matchable_intents.append(i)
        tempoutput.append('.')
output.append(''.join(tempoutput))

output.append('')
output.append("Matchable intents: %s" % len(matchable_intents))


# TODO: use within_radius for matchability test above as well.
def within_radius(a, b):
    distance = float((a.radius + b.radius) / 10)
    pair_distance = geopy.distance.distance((i.lat, i.lng), 
            (other.lat, other.lng)).km
    return (distance - pair_distance) > 0
        
def all(seq, pred=None):
    "Returns True if pred(x) is true for every element in the iterable"
    for elem in itertools.ifilterfalse(pred, seq):
        return False
    return True

output.append("#" * 70)
# super naive and inefficient matching. 
used_ids = sets.Set()
for i in matchable_intents:
    matches = []
    if i.id in used_ids:
        continue  # skip intents if they've already been matched in the loop
    matches.append(i)
    for other in matchable_intents:
        if len(matches) >= MAX_SIZE: # don't make groups too large
            continue
        if (i.id != other.id 
                and i.person_id != other.person_id
                and other.id not in used_ids):
            if all(within_radius(item, other) for item in matches):
                matches.append(other)
                used_ids.add(other.id)

    if len(matches) > 1:
        used_ids.add(i.id)
    else:
        continue

    output.append(pformat(matches))
    if not pretend:
        match = Match(date=i.date)
        match.save()
    for intent in matches:
        if not pretend:
            message = 'Matched %s on %s' % (
                    intent.person.email, match.date)
            im = IntentMatch(intent = intent, match = match)
            im.save()
            intent.status = 'matched'
            intent.save()
            l = Log(intent = intent, action = 'matched', message = message)
            l.save()

# TODO: deal with orphaned matches - should never happen but it does?

output.append("#" * 70)
for i in matchable_intents:
    if i.id not in used_ids:
        message = 'No match found for %s on %s (I:%s)' % (
                i.person.email, i.date, i.id)
        output.append(message)
        if not pretend:
            i.status = 'match_failed'
            i.save()

            l = Log(intent = i, action = 'match_failed', message = message)
            l.save()


print '\n'.join(output)

    

